/**
 * 
 */
package org.stars.dao.sqlmapper.parser;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.stars.config.Message;
import org.stars.dao.sqlmapper.Parameter;
import org.stars.dao.sqlmapper.SqlBase;
import org.stars.dao.sqlmapper.SqlDefinition;
import org.stars.dao.sqlmapper.SqlFragment;
import org.stars.dao.sqlmapper.SqlMapper;
import org.stars.dao.sqlmapper.typealias.TypeAliasUtils;
import org.stars.dao.sqlmapper.typehandlers.TypeHandlerAttribute;

/**
 * Find parameters in query string. Replace with a ? in templateText and obtain
 * a list of parameters.
 * 
 * For every parameter detect attributes.
 * 
 * @author Francesco Benincasa
 * 
 */
public abstract class SubParser06_FindParameters {
	
	protected transient static Log log=LogFactory.getLog(SubParser06_FindParameters.class);

	/**
	 * pattern for parameter
	 * 
	 * #\s*\[\s*(\w+)((\s*,\s*([\w\.]+)\s*=\s*([\w\.]+)\s*)*\s*)\]
	 */
	private final static String REG_EX = "#\\s*\\[\\s*(\\w+)((\\s*,\\s*([\\w\\.]+)\\s*=\\s*([\\w\\.]+)\\s*)*\\s*)\\]";

	private final static String REPLACED_VALUE = "?";

	private final static int GROUP_PARAM_NAME = 1;
	private final static int GROUP_PARAM_ATTRIBUTES = 2;

	/**
	 * Matcher compilato.
	 */
	private static Pattern pattern = Pattern.compile(REG_EX, Pattern.MULTILINE);

	public static boolean execute(SqlMapper sqlMapper) throws Exception {
		for (SqlDefinition item : sqlMapper.getMap().values()) {
			execute(item, item);
		}

		return true;
	}

	public static void execute(SqlDefinition definition, SqlBase sqlBase) {

		if (sqlBase.getParts().size() == 0) {
			String sql = sqlBase.getTemplateText();
			SubParser06_Result result = execute(sql);

			if (result.isElaborated())
			{
				// there are found parameters, so put in sqlBase
				sqlBase.setTemplateText(result.getSqlText());
				sqlBase.setParameters(result.getParameters());
			}
		} else {
			// there are parts, so analyze them.
			for (SqlFragment item : sqlBase.getParts()) {
				execute(definition, item);
			}
		}
	}

	/**
	 * Parse the input string to separate parameters from sql code.
	 * 
	 * @param input
	 * @return
	 */
	public static SubParser06_Result execute(String input) {
		// dobbiamo per sicurezza rimuovere i caratteri prima e dopo
		SubParser06_Result result = new SubParser06_Result();
		List<Parameter> parameters = new ArrayList<Parameter>();
		Parameter param;

		Matcher matcher = pattern.matcher(input);
		StringBuffer sb = new StringBuffer();

		String temp1;
		String temp2;
		String[] temp3;
		String[] temp4;

		boolean found = false;

		while (matcher.find()) {
			found = true;
			matcher.appendReplacement(sb, REPLACED_VALUE);

			param = new Parameter();

			temp1 = matcher.group(GROUP_PARAM_NAME).trim();
			temp2 = matcher.group(GROUP_PARAM_ATTRIBUTES).trim();

			param.setName(temp1);

			temp3 = temp2.split(",");
			int i = 0;
			for (String item : temp3) {
				
				if (i++ == 0)
					continue;
				temp4 = item.split("=");
				param.getAttributes().put(temp4[0].trim(), temp4[1].trim());
			}
			parameters.add(param);
		}

		if (found) {
			// found paramateres, so set elaborated true
			matcher.appendTail(sb);

			result.setSqlText(sb.toString());
			result.setParameters(parameters);
			
			result.setElaborated(true);
		} else {
			// nothing found, so set elaborated false
			result.setParameters(parameters);
			result.setSqlText(input);
			result.setElaborated(false);
		}
		
		
		TypeHandlerAttribute attribute;
		// estrapolate some particular attribute
		for (Parameter item: result.getParameters())
		{
			for (Entry<String, String> item1: item.getAttributes().entrySet())
			{
				attribute=TypeHandlerAttribute.parse(item1.getKey());
				
				if (attribute==null) continue;
								
				switch(attribute)
				{
				case HANDLER:
					try {
					item.setTypeHandler(TypeAliasUtils.resolveClass(item1.getValue()));
					} catch (Exception e) {
						log.error(Message.SUBPARSER06_01_ERROR.with(item1.getValue(), item1.getKey()));
					}
					break;
				}
			}
		}
		
		return result;
	}
}
